#include "Player.h"
#include "Game.h"
#include "Board.h"
#include "Consolebox.h"
#include "Card.h"

#define JAIL_OFFSET 2

Player::Player()
{

}

void Player::Init(Game* a_game, char a_avatar, int a_playerNum)
{
	m_game = a_game;
	m_space = 0;
	m_space = 0;
	m_avatar = a_avatar;
	m_playerNum = a_playerNum;
	m_inJail = 0;
	m_state = STANDING;
	m_targetSpace = 0;
	m_doubles = 0;
	m_money = 1500;
	m_moving = 0;
	m_curInventory = 0;
	m_tradeInventory = 0;
	m_bankrupt = 0;

	for(int i = 0; i < NUM_COLORS; i++)
		m_colorsOwned[i] = 0;
}

void Player::Update()
{
	m_lastSpace = m_space;
	
	switch(m_state)
	{
	case FINISHED_TURN:
		m_state = STANDING;
		if(!getDoubles())
		{
			m_game->NextPlayer();
			m_game->setWaiting(false);
		}
		else
		{
			m_game->cBox->AddString("You got doubles,\nroll again!");
			m_game->setWaiting(false);
		}
		break;
	case MOVING:
		MoveForward();

		m_moving--;
		if(m_moving <= 0)
		{
			m_state = LANDED;
		}
		break;
	case MOVING_TO_SPACE:
		// You have arrived!
		if(m_space == m_targetSpace)
			m_state = LANDED;
		else // Keep goin'
			MoveForward();
		break;
	case LANDED:
		// Landed on a space (obviously)
		doLandingLogic();
		break;
	case STANDING:
		// Just hangin' out.
		break;
	case ANSWERING:
		break;
	case TRADING:
		for(int i = 0; i < NUM_PLAYERS; i++)
		{
			if(&m_game->players[i] != this)	//if not this player
				trade(&m_game->players[i]);
		}
		break;
	case TRADED:
		for(int i = 0; i < NUM_PLAYERS; i++)
		{
			if(&m_game->players[i] != this)	//if not this player
				tradeProperty(&m_game->players[i]);
		}
		m_state = STANDING;
		m_game->setState(G_PLAYING);
		ClearScreen();
		break;

	}

	if(getDoubles() >= 3)
	{
		// GO TO JAIL
		GoToJail();
		resetDoubles();
	}
}

void Player::GoToJail()
{
	GoToSpace(m_game->searchSpace("Jail", m_space));
	incrementInJail();
}

int Player::getDoubles() { return m_doubles; }

void Player::resetDoubles()	{ m_doubles = 0; }

void Player::incrementDoubles()	{ m_doubles++; }

void Player::MoveNumSpaces(int a_spaces) { m_moving = a_spaces; m_state = MOVING; }

// returns -1 if the player just finished moving.
bool Player::isMoving() { return m_space != m_lastSpace; }

void Player::MoveForward()
{
	m_space++;

	// Starting over at the start of the board
	if(m_space == 40)
		m_space = 0;

	// Moving past/landing on go!
	if(m_space == 0 && !isInJail())
	{
		m_game->cBox->AddString("You got a refund check.\nCollect $200!");
		GiveMoney(200);
		StupidHack();
	}
}

/* Is also the draw function**/
int Player::CheckInBoundaries(int a_boardX, int a_boardY, int a_offsX, int a_offsY, bool draw)
{
	short x = m_playerNum + 1; // Make sure the players don't all occupy the exact same space
	short y = 2; // Kinda in the center of the box
	const int sizeOfSquareX = 9;
	const int sizeOfSquareY = 4;

	// Magic numbers galore..

	if(m_space > 30) // Going up the left side
	{
		y += 10 * sizeOfSquareY - ((m_space - 30) * sizeOfSquareY);
	}
	else if(m_space > 20) // Going across the bottom
	{
		x += 10 * sizeOfSquareX - ((m_space - 20) * sizeOfSquareX);
		y += 10 * sizeOfSquareY;

	}
	else if(m_space > 10) // Going down the right side
	{
		x += 10 * sizeOfSquareX;
		y += (m_space - 10) * sizeOfSquareY;
	}
	else // Going across the top
	{
		x += m_space * sizeOfSquareX;
	}

	// Only draw the piece if it's actually ON the board.
	// Set the correct offsets (for moving the camera)
	x -= a_offsX;
	y -= a_offsY;

	// Off the left of the board
	if(x < 0)
		return MOVE_CAM_LEFT;
	// off the top of the board
	if(y < 0) 
		return MOVE_CAM_UP;

	// Move it to the position of the board
	x += a_boardX;
	y += a_boardY;

	// Off the right of the board
	if(x > VIEW_WIDTH + a_boardX - 1)
		return MOVE_CAM_RIGHT;
	// Off the bottom of the board
	if(y > VIEW_HEIGHT + a_boardY - 1)
		return MOVE_CAM_DOWN;

	// Draw the avatar
	if(draw)
	{
		if(isInJail())
			gotoXY(x,y+JAIL_OFFSET);
		else
			gotoXY(x, y);
		_putch(m_avatar);
	}

	return 1;
}

void Player::DrawInventory()
{
	if(m_inventory.size())
		m_inventory[m_curInventory]->Draw(INVENTORY_X, INVENTORY_Y);
}

int Player::getSpace() { return m_space; }

void Player::GoToSpace(int a_space)
{
	m_targetSpace = a_space;
	m_state = MOVING_TO_SPACE;
}

void Player::releaseFromJail() { m_inJail = !m_inJail; }

int Player::isInJail() { return m_inJail; }

void Player::incrementInJail() { m_inJail++; }

void Player::RollLogic(int a_roll1, int a_roll2)
{
	m_roll = a_roll1 + a_roll2;

	// Player rolled doubles
	if(a_roll1 == a_roll2)
	{
		incrementDoubles();
		
		// If you were in jail before.. you're out now, buddy. Grats!
		if(isInJail())
		{
			releaseFromJail();

			m_game->cBox->AddString("Released from jail!");
			StupidHack();
		}
	}
	else
	{
		if(isInJail())
		{
			incrementInJail();

			if(isInJail() == 4)
			{
				m_game->cBox->AddString("Rolled 3 times in jail, pay 50 bux");
				PayBank(50);
				releaseFromJail();

				StupidHack();
			}
			else
			{
				m_game->cBox->AddString("Didn't roll doubles, you're stuck.");
				StupidHack();
			}

			m_state = FINISHED_TURN;
		}

		resetDoubles();
	}

	// Make the player move (If not in jail)
	if(!isInJail())
		MoveNumSpaces(m_roll);
}

int Player::PayPlayer(Player* a_payee, int a_money)
{
	if(m_money - a_money < 0)
		return m_money - a_money; // Not enough cash!

	m_money -= a_money;
	a_payee->GiveMoney(a_money);

	return 1;
}

void Player::GetMoneyFromPlayer(Player* a_payer, int a_money)
{
	a_payer->PayPlayer(this, a_money);
}


void Player::PayBank(int a_money)
{
	m_money -= a_money;
}

void Player::buyAHouse()
{
	if(!m_inventory.size())
		return;
	
	int color = m_inventory[m_curInventory]->getColor();

	// You have the right properties
	if(m_colorsOwned[color] == m_game->properties->getNumPropsPerColor(color)) // AHHHHH
	{
		Property* inv = m_inventory[m_curInventory];
		int price = inv->getPricePerHouse();
	
		// Have enough money
		if(m_money > price)
		{
			// Wrong kind of property
			if(inv->getColor() == UTILITY || inv->getColor() == TRAIN)
			{
				m_game->cBox->AddString("You can't add houses\nto this kind of property!");
			}
			// Bought a house!
			else if(inv->addHouse())
			{
				m_money -= price;

				if(inv->getHouses() == 5)
					m_game->cBox->AddString("Bought a HOTEL");
				else
					m_game->cBox->AddString("Bought a house");
			}
			else
			{
				m_game->cBox->AddString("You cannot improve\nthis property any\nmore.");
			}
			
		}
		// Not enough money
		else
		{
			m_game->cBox->AddString("Not enough money to\nbuy a house.");				
		}
	}

	// You do not have the right properties
	else
	{
		m_game->cBox->AddString("You do not own the\nnecessary propertiesto buy a house.");
	}
}

void Player::sellAHouse()
{
	Property* inv = m_inventory[m_curInventory]; // SAVE ME TYPING!

	if(!m_inventory.size())
		return;

	// Wrong kind of property
	if(inv->getColor() == UTILITY || inv->getColor() == TRAIN)
	{
		m_game->cBox->AddString("You can't add houses\nto this kind of property!");
	}
	else
	{
		// Try to remove a house
		if(inv->removeHouse())
		{
			m_money += inv->getPricePerHouse();
			m_game->cBox->AddString("Sold a house!");
		}
		else // Didn't have any houses!
			m_game->cBox->AddString("This property doesn't have\nany houses!");

	}
}

void Player::mortgageAProperty()
{
	Property* inv = m_inventory[m_curInventory];

	// Can't mortgage with houses on it
	if(inv->getHouses() > 0
		&& inv->getColor() != UTILITY
		&& inv->getColor() != TRAIN)
	{
		m_game->cBox->AddString("You cannot mortgage\nproperties with houses\non them.\nSell your houses first.");
	}
	else
	{
		// Mortgage a property
		if(!inv->isMortgaged())
		{
			inv->toggleMortgaged();
			m_money += inv->getMortgageValue();
			m_game->cBox->AddString("Mortgaged the property!");
		}
		// Demortgage a property
		else
		{
			if(m_money > inv->getMortgageValue())
			{
				inv->toggleMortgaged();
				m_money -= inv->getMortgageValue();
				m_game->cBox->AddString("Demortgaged the property!");
			}
			else // Not enough cash.
				m_game->cBox->AddString("Not enough money to\ndemortgage this property.");
		}
	}
}

void Player::handleInput(int a_input)
{
	switch(a_input)
	{
	case 'y':
		if(m_state == ANSWERING)
		{
			Space* curSpace = m_game->getSpace(m_space);

			// Buy the property
			m_inventory.push_back(curSpace->BuyProperty(this));

			// We now own one more of this color
			m_colorsOwned[curSpace->getColor()]++; 
			m_state = FINISHED_TURN;
		}
		else if(m_state == TRADING)
		{
			m_state = TRADED;
		}
		break;
	case 'n':
		if(m_state == ANSWERING)
		{
			m_state = FINISHED_TURN; 
		}
		break;
	case 'm': // Mortgage a property
		// To mortgage a property, you must sell all your houses!
		mortgageAProperty();
		break;
	case 'b': // Buy a house
		buyAHouse();
		break;
	case 's': // Sell a house
		sellAHouse();
		break;
	case 'x':
		m_bankrupt = true;
		PayBank(99999); // Muwahahaha
		m_game->NextPlayer();
		break;
	case ',':
		if(m_inventory.size() == 0)
			return;

		// Cycle inventory left
		m_curInventory--;
		if(m_curInventory < 0)
			m_curInventory = m_inventory.size()-1;

		break;
	case '.':
		if(m_inventory.size() == 0)
			return;

		// Cycle inventory right
		m_curInventory++;
		if(m_curInventory >= m_inventory.size()-1)
			m_curInventory = 0;

		break;
	case 't':
		//if(m_state == STANDING)
			m_state = TRADING;
		ClearScreen();
		break;
/*	case ';':
		if(m_inventory.size() == 0)
			return;

		// Cycle inventory left
		m_tradeInventory--;
		if(m_tradeInventory < 0)
			m_tradeInventory = 0;

		break;
	case 'l':
		if(m_inventory.size() == 0)
			return;

		// Cycle inventory right
		m_curInventory++;
		if(m_curInventory >= m_inventory.size()-1)
			m_curInventory = 0;

		break;
*/
	}
}

void Player::doCardLogic(Card* c)
{
	// Print out the contents of the card.
	m_game->cBox->AddString(c->getFlavorText());

	// We're done with our turn after this
	m_state = FINISHED_TURN;

	// Do the logic based on the type.
	switch(c->getType())
	{
	case CT_PAY:
		PayBank(c->getAmount());
		break;
	case CT_PAYPLAYERS:
		for(int i = 0; i < NUM_PLAYERS; i++)
		{
			if(&m_game->players[i] != this) // Dont give yourself money? >_>
				PayPlayer(&m_game->players[i], c->getAmount());
		}
		break;
	case CT_COLLECT:
		GiveMoney(c->getAmount());
		break;
	case CT_COLLECTPLAYERS:
		for(int i = 0; i < NUM_PLAYERS; i++)
		{
			if(&m_game->players[i] != this) // Don't get money from yourself? <_<
				GetMoneyFromPlayer(&m_game->players[i], c->getAmount());
		}
		break;
	case CT_JAIL:
		GoToJail();
		break;
	case CT_GOTOSPACE:
		{
			char* spc = c->getDestination();

			if(strncmp(spc,"back3", 20) == 0) // Special case
			{
				// Move forward, not back. Meh.
				int spaceChange = m_space+3;
				if(m_space > NUM_SPACES)
					spaceChange = m_space-NUM_SPACES;
				
				GoToSpace(spaceChange);
			}
			else
				GoToSpace(m_game->searchSpace(spc, m_space));
			break;
		}
	case CT_OUTOFJAIL:
		// Just because get out of jail cards are stupid and this
		// is all they amount to.
		GiveMoney(50);
		break;
	case CT_PAYPERHOUSE:
		{
			int houses = 0;
			int hotels = 0;
			int curHouses;

			for(int i = 0; i < m_inventory.size(); i++)
			{
				curHouses = m_inventory[i]->getHouses();
				
				// Keep track of all the houses
				if(curHouses < 5)
					houses += curHouses;
				else
					hotels++;
			}

			// Pay the amount required by the card
			PayBank(houses*c->getAmount());
			PayBank(hotels*c->getSecondaryAmount());
			break;
		}
		
	}
}

void Player::StupidHack()
{
	// stupid hack because I'm running out of time
	m_game->cBox->AddString("\nPress any key");
	m_game->cBox->Draw();
	_getch();
}

void Player::doLandingLogic()
{
	Space* curSpace = m_game->getSpace(m_space);
	int owner = curSpace->getOwner();

	if(owner == -1) // Unowned
	{
		char msg[64];
		sprintf_s(msg, "Would you\nlike to buy\n%s?\n(Y/N)", curSpace->getName());
		m_game->cBox->AddString(msg);

		m_state = ANSWERING;
	}
	else if(owner == -2) // Not a property
	{
		char* name = curSpace->getName();
		// Landed on a special space
		if(strncmp("Threaded Discussion", name, 20) == 0)
		{
			m_game->cBox->AddString("Landed on Threaded Discussions.\n");
			doCardLogic(m_game->pickupChanceCard());
			
			StupidHack();
		}
		else if(strncmp("Library", name, 20) == 0)
		{
			m_game->cBox->AddString("Landed on Library.\n");
			doCardLogic(m_game->pickupCommunityChestCard());
			
			StupidHack();
		}
		else if(strncmp("Go To Finance", name, 20) == 0)
		{
			GoToJail();
			m_game->cBox->AddString("Go straight to jail!\nDo not pass go.\nDo not collect $200");
		}
		else // Probably a tax space.
		{
			char tmp[32];
			int price = curSpace->getPrice();
			
			if(price != 0 && m_space != 0) // Failsafe for other special spaces
			{
				sprintf_s(tmp, "Pay the bank $%d.", price);
				PayBank(curSpace->getPrice());

				m_game->cBox->AddString(tmp);

				StupidHack();
			}
			m_state = FINISHED_TURN;
		}
	}
	else
	{
		// Why would I want to pay money to myself?
		if(&m_game->players[owner] == this)
		{
			m_state = FINISHED_TURN;
			return;
		}

		// Don't pay anyone that's bankrupt.
		if(m_game->players[owner].isBankrupt())
		{
			m_game->cBox->AddString("Owner is bankrupt.\nFree parking!");
			StupidHack();
			m_state = FINISHED_TURN;
			return;
		}

		// Pay the owner
		int amtRqd = PayPlayer(&m_game->players[owner], curSpace->getRent(m_roll));
		char msg[128];	
		
		// Not enough money? Better sell some stuff.
		if(amtRqd < 0)
		{	
			sprintf_s(msg, "You need $%d!\nCycle through your\ninventory with\n< and >\npress M to mortgage,S to sell a house,\nor X to go bankrupt.", abs(amtRqd));
			m_game->cBox->AddString(msg);
		}
		else if(amtRqd == 0)
			m_game->cBox->AddString("The property is mortaged.\nAs such, rent is free!");
		else 
		{
			sprintf_s(msg, "Paid Player %d\n$%d", owner+1, curSpace->getRent(m_roll));
			m_game->cBox->AddString(msg);

			StupidHack();

			m_state = FINISHED_TURN;
		}
	}
}

void Player::trade(Player *a_trader)							//new function added by jekko
{
	//print to console
	m_game->cBox->AddString("Select property\nto trade.");
	//draw trading player's inventory
	m_inventory[m_curInventory]->Draw(2,2);
	//draw other player's inventory
	a_trader->m_inventory[m_curInventory]->Draw(24,2);
}

void Player::tradeProperty(Player *a_trader)					//new function added by jekko that NEEDS HELP!
{
	Property* temp;
	temp = a_trader->m_inventory[m_curInventory];

	

	// Add the properties
	a_trader->m_inventory.push_back(m_inventory[m_curInventory]);
	m_inventory.push_back(a_trader->m_inventory[m_curInventory]);

	// Erase the properties
	a_trader->m_inventory.erase(a_trader->m_inventory.begin() + m_curInventory);
	m_inventory.erase(m_inventory.begin() + m_curInventory);

	// Set the owners
	m_inventory[m_curInventory]->setOwner(this);
	a_trader->m_inventory[m_curInventory]->setOwner(a_trader);
}